﻿/****************************************************************************
 * Copyright (c) 2015 ~ 2022 liangxiegame MIT License
 *
 * QFramework v1.0
 *
 * https://qframework.cn
 * https://github.com/liangxiegame/QFramework
 *
 * Author:
 *  liangxie
 *  王二 soso
 * Contributor
 *  TastSong
 *
 * Community
 *  QQ Group: 623597263
 ****************************************************************************/

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using Object = UnityEngine.Object;

namespace QFramework
{
    #region Architecture

    public interface IArchitecture
    {
        /// <summary>
        ///     注册系统
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        void RegisterSystem<T>(T instance) where T : ISystem;

        /// <summary>
        ///     注册 Model
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        void RegisterModel<T>(T instance) where T : IModel;

        /// <summary>
        ///     注册工具
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        void RegisterUtility<T>(T instance) where T : IUtility;

        /// <summary>
        ///     获取 System
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetSystem<T>() where T : class, ISystem;

        /// <summary>
        ///     获取 Model
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetModel<T>() where T : class, IModel;

        /// <summary>
        ///     获取工具
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetUtility<T>() where T : class, IUtility;

        /// <summary>
        ///     发送命令
        /// </summary>
        /// <typeparam name="T"></typeparam>
        void SendCommand<T>() where T : ICommand, new();

        /// <summary>
        ///     发送命令
        /// </summary>
        /// <param name="command"></param>
        /// <typeparam name="T"></typeparam>
        void SendCommand<T>(T command) where T : ICommand;

        /// <summary>
        ///     发送事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        void SendEvent<T>() where T : new();

        /// <summary>
        ///     发送事件
        /// </summary>
        /// <param name="e"></param>
        /// <typeparam name="T"></typeparam>
        void SendEvent<T>(T e);

        /// <summary>
        ///     注册事件
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        IUnRegister RegisterEvent<T>(Action<T> onEvent);

        /// <summary>
        ///     注销事件
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        void UnRegisterEvent<T>(Action<T> onEvent);

        TResult SendQuery<TResult>(IQuery<TResult> query);
    }

    /// <summary>
    ///     架构
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class Architecture<T> : IArchitecture where T : Architecture<T>, new()
    {
        private readonly IocContainer _container = new();

        /// <summary>
        ///     用于初始化的 Models 的缓存
        /// </summary>
        private readonly List<IModel> _models = new();

        /// <summary>
        ///     用于初始化的 Systems 的缓存
        /// </summary>
        private readonly List<ISystem> _systems = new();

        private readonly ITypeEventSystem _typeEventSystem = new TypeEventSystem();

        /// <summary>
        ///     是否已经初始化完成
        /// </summary>
        private bool _inited;

        // 注册系统
        public void RegisterSystem<TSystem>(TSystem instance) where TSystem : ISystem
        {
            // 需要给 System 赋值一下
            instance.SetArchitecture(this);
            _container.Register(instance);

            // 如果初始化过了
            if (_inited)
                instance.Init();
            else
                // 添加到 System 缓存中，用于初始化
                _systems.Add(instance);
        }

        // 注册 Model
        public void RegisterModel<TModel>(TModel instance) where TModel : IModel
        {
            // 需要给 Model 赋值一下
            instance.SetArchitecture(this);
            _container.Register(instance);

            // 如果初始化过了
            if (_inited)
                instance.Init();
            else
                // 添加到 Model 缓存中，用于初始化
                _models.Add(instance);
        }

        // 注册 Utility
        public void RegisterUtility<TUtility>(TUtility instance) where TUtility : IUtility
        {
            _container.Register(instance);
        }

        // 获取 System
        public TSystem GetSystem<TSystem>() where TSystem : class, ISystem
        {
            return _container.Get<TSystem>();
        }

        // 获取 Model
        public TModel GetModel<TModel>() where TModel : class, IModel
        {
            return _container.Get<TModel>();
        }

        // 获取 Utility
        public TUtility GetUtility<TUtility>() where TUtility : class, IUtility
        {
            return _container.Get<TUtility>();
        }

        public void SendCommand<TCommand>() where TCommand : ICommand, new()
        {
            var command = new TCommand();
            command.SetArchitecture(this);
            command.Execute();
        }

        public void SendCommand<TCommand>(TCommand command) where TCommand : ICommand
        {
            command.SetArchitecture(this);
            command.Execute();
        }

        public void SendEvent<TEvent>() where TEvent : new()
        {
            _typeEventSystem.Send<TEvent>();
        }

        public void SendEvent<TEvent>(TEvent e)
        {
            _typeEventSystem.Send(e);
        }

        public IUnRegister RegisterEvent<TEvent>(Action<TEvent> onEvent)
        {
            return _typeEventSystem.Register(onEvent);
        }

        public void UnRegisterEvent<TEvent>(Action<TEvent> onEvent)
        {
            _typeEventSystem.UnRegister(onEvent);
        }

        public TResult SendQuery<TResult>(IQuery<TResult> query)
        {
            query.SetArchitecture(this);
            return query.Do();
        }

        // 留给子类注册模块
        protected abstract void Init();

        // 提供一个注册模块的 API
        public static void Register<T1>(T1 instance)
        {
            MakeSureContainer();
            _architecture._container.Register(instance);
        }

        #region 类似单例模式 但是仅在内部可访问

        /// <summary>
        ///     增加注册
        /// </summary>
        public static Action<T> OnRegisterPatch = architecture => { };

        private static T _architecture;

        public static IArchitecture Interface
        {
            get
            {
                if (_architecture == null) MakeSureContainer();

                return _architecture;
            }
        }

        // 确保 Container 是有实例的
        private static void MakeSureContainer()
        {
            if (_architecture == null)
            {
                _architecture = new T();
                _architecture.Init();

                // 调用
                OnRegisterPatch?.Invoke(_architecture);

                // 初始化 Model
                foreach (var architectureModel in _architecture._models) architectureModel.Init();

                // 清空 Model
                _architecture._models.Clear();

                // 初始化 System
                foreach (var architectureSystem in _architecture._systems) architectureSystem.Init();

                // 清空 System
                _architecture._systems.Clear();

                _architecture._inited = true;
            }
        }

        #endregion
    }

    #endregion

    #region Controller

    public interface IController : IBelongToArchitecture, ICanGetSystem, ICanGetModel, ICanSendCommand,
        ICanRegisterEvent, ICanSendQuery
    {
    }

    #endregion

    #region System

    public interface ISystem : IBelongToArchitecture, ICanSetArchitecture, ICanGetModel, ICanGetUtility, ICanSendEvent,
        ICanRegisterEvent, ICanGetSystem
    {
        void Init();
    }

    public abstract class AbstractSystem : ISystem
    {
        private IArchitecture _architecture;

        void ISystem.Init()
        {
            OnInit();
        }

        IArchitecture IBelongToArchitecture.GetArchitecture()
        {
            return _architecture;
        }

        void ICanSetArchitecture.SetArchitecture(IArchitecture architecture)
        {
            _architecture = architecture;
        }

        protected abstract void OnInit();
    }

    #endregion

    #region Model

    public interface IModel : IBelongToArchitecture, ICanSetArchitecture, ICanGetUtility, ICanSendEvent
    {
        void Init();
    }

    public abstract class AbstractModel : IModel
    {
        private IArchitecture _architecture;

        void IModel.Init()
        {
            OnInit();
        }

        IArchitecture IBelongToArchitecture.GetArchitecture()
        {
            return _architecture;
        }

        void ICanSetArchitecture.SetArchitecture(IArchitecture architecture)
        {
            _architecture = architecture;
        }

        protected abstract void OnInit();
    }

    #endregion

    #region Utility

    public interface IUtility
    {
    }

    #endregion

    #region Command

    public interface ICommand : IBelongToArchitecture, ICanSetArchitecture, ICanGetSystem, ICanGetModel, ICanGetUtility,
        ICanSendCommand, ICanSendEvent, ICanSendQuery
    {
        internal void Execute();
    }

    public abstract class AbstractCommand : ICommand
    {
        private IArchitecture _architecture;

        void ICommand.Execute()
        {
            OnExecute();
        }

        IArchitecture IBelongToArchitecture.GetArchitecture()
        {
            return _architecture;
        }

        void ICanSetArchitecture.SetArchitecture(IArchitecture architecture)
        {
            _architecture = architecture;
        }

        protected abstract void OnExecute();
    }

    #endregion

    #region Query

    public interface IQuery<T> : IBelongToArchitecture, ICanSetArchitecture, ICanGetModel, ICanGetSystem, ICanGetUtility
    {
        T Do();
    }

    public abstract class AbstractQuery<T> : IQuery<T>
    {
        private IArchitecture _architecture;

        public T Do()
        {
            return OnDo();
        }

        public IArchitecture GetArchitecture()
        {
            return _architecture;
        }

        public void SetArchitecture(IArchitecture architecture)
        {
            _architecture = architecture;
        }

        protected abstract T OnDo();
    }

    #endregion

    #region Rule

    public interface IBelongToArchitecture
    {
        IArchitecture GetArchitecture();
    }

    public interface ICanSetArchitecture
    {
        void SetArchitecture(IArchitecture architecture);
    }

    public interface ICanGetModel : IBelongToArchitecture
    {
    }

    public static class CanGetModelExtension
    {
        public static T GetModel<T>(this ICanGetModel self) where T : class, IModel
        {
            return self.GetArchitecture().GetModel<T>();
        }
    }

    public interface ICanGetSystem : IBelongToArchitecture
    {
    }

    public static class CanGetSystemExtension
    {
        public static T GetSystem<T>(this ICanGetSystem self) where T : class, ISystem
        {
            return self.GetArchitecture().GetSystem<T>();
        }
    }

    public interface ICanGetUtility : IBelongToArchitecture
    {
    }

    public static class CanGetUtilityExtension
    {
        public static T GetUtility<T>(this ICanGetUtility self) where T : class, IUtility
        {
            return self.GetArchitecture().GetUtility<T>();
        }
    }

    public interface ICanRegisterEvent : IBelongToArchitecture
    {
    }

    public static class CanRegisterEventExtension
    {
        public static IUnRegister RegisterEvent<T>(this ICanRegisterEvent self, Action<T> onEvent)
        {
            return self.GetArchitecture().RegisterEvent(onEvent);
        }

        public static void UnRegisterEvent<T>(this ICanRegisterEvent self, Action<T> onEvent)
        {
            self.GetArchitecture().UnRegisterEvent(onEvent);
        }
    }

    public interface ICanSendCommand : IBelongToArchitecture
    {
    }

    public static class CanSendCommandExtension
    {
        public static void SendCommand<T>(this ICanSendCommand self) where T : ICommand, new()
        {
            self.GetArchitecture().SendCommand<T>();
        }

        public static void SendCommand<T>(this ICanSendCommand self, T command) where T : ICommand
        {
            self.GetArchitecture().SendCommand(command);
        }
    }

    public interface ICanSendEvent : IBelongToArchitecture
    {
    }

    public static class CanSendEventExtension
    {
        public static void SendEvent<T>(this ICanSendEvent self) where T : new()
        {
            self.GetArchitecture().SendEvent<T>();
        }

        public static void SendEvent<T>(this ICanSendEvent self, T e)
        {
            self.GetArchitecture().SendEvent(e);
        }
    }

    public interface ICanSendQuery : IBelongToArchitecture
    {
    }

    public static class CanSendQueryExtension
    {
        public static T SendQuery<T>(this ICanSendQuery self, IQuery<T> query)
        {
            return self.GetArchitecture().SendQuery(query);
        }
    }

    #endregion

    #region TypeEventSystem

    public interface ITypeEventSystem
    {
        /// <summary>
        ///     发送事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        void Send<T>() where T : new();

        /// <summary>
        ///     发送事件
        /// </summary>
        /// <param name="e"></param>
        /// <typeparam name="T"></typeparam>
        void Send<T>(T e);

        /// <summary>
        ///     注册事件
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        IUnRegister Register<T>(Action<T> onEvent);

        /// <summary>
        ///     注销事件
        /// </summary>
        /// <param name="onEvent"></param>
        /// <typeparam name="T"></typeparam>
        void UnRegister<T>(Action<T> onEvent);
    }

    /// <summary>
    ///     用于注销的接口
    /// </summary>
    public interface IUnRegister
    {
        void UnRegister();
    }

    /// <summary>
    ///     注销接口的实现
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class TypeEventSystemUnRegisger<T> : IUnRegister
    {
        public ITypeEventSystem TypeEventSystem { get; set; }
        public Action<T> OnEvent { get; set; }

        public void UnRegister()
        {
            TypeEventSystem.UnRegister(OnEvent);

            TypeEventSystem = null;
            OnEvent = null;
        }
    }

    /// <summary>
    ///     注销的触发器
    /// </summary>
    public class UnRegisterOnDestroyTrigger : MonoBehaviour
    {
        private readonly HashSet<IUnRegister> _unRegisters = new();

        private void OnDestroy()
        {
            foreach (var unRegister in _unRegisters) unRegister.UnRegister();

            _unRegisters.Clear();
        }

        public void AddUnRegister(IUnRegister unRegister)
        {
            _unRegisters.Add(unRegister);
        }
    }

    /// <summary>
    ///     注销触发器的使用简化
    /// </summary>
    public static class UnRegisterExtension
    {
        public static void UnRegisterWhenGameObjectDestroyed(this IUnRegister unRegister, GameObject gameObject)
        {
            var trigger = gameObject.GetComponent<UnRegisterOnDestroyTrigger>();

            if (!trigger) trigger = gameObject.AddComponent<UnRegisterOnDestroyTrigger>();

            trigger.AddUnRegister(unRegister);
        }
    }

    public class TypeEventSystem : ITypeEventSystem
    {
        public static readonly TypeEventSystem Global = new();

        private readonly Dictionary<Type, IRegistrations> _eventRegistrations = new();

        public void Send<T>() where T : new()
        {
            var e = new T();
            Send(e);
        }

        public void Send<T>(T e)
        {
            var type = typeof(T);
            IRegistrations eventRegistrations;

            if (_eventRegistrations.TryGetValue(type, out eventRegistrations))
                ((Registrations<T>) eventRegistrations).OnEvent.Invoke(e);
        }

        public IUnRegister Register<T>(Action<T> onEvent)
        {
            var type = typeof(T);
            IRegistrations eventRegistrations;

            if (_eventRegistrations.TryGetValue(type, out eventRegistrations))
            {
            }
            else
            {
                eventRegistrations = new Registrations<T>();
                _eventRegistrations.Add(type, eventRegistrations);
            }

            ((Registrations<T>) eventRegistrations).OnEvent += onEvent;

            return new TypeEventSystemUnRegisger<T>
            {
                OnEvent = onEvent,
                TypeEventSystem = this
            };
        }

        public void UnRegister<T>(Action<T> onEvent)
        {
            var type = typeof(T);
            IRegistrations eventRegistrations;

            if (_eventRegistrations.TryGetValue(type, out eventRegistrations))
                ((Registrations<T>) eventRegistrations).OnEvent -= onEvent;
        }

        private interface IRegistrations
        {
        }

        private class Registrations<T> : IRegistrations
        {
            /// <summary>
            ///     因为委托本身就可以一对多注册
            /// </summary>
            public Action<T> OnEvent = obj => { };
        }
    }

    public interface IOnEvent<T>
    {
        void OnEvent(T e);
    }

    public static class OnGlobalEventExtension
    {
        public static IUnRegister RegisterEvent<T>(this IOnEvent<T> self) where T : struct
        {
            return TypeEventSystem.Global.Register<T>(self.OnEvent);
        }

        public static void UnRegisterEvent<T>(this IOnEvent<T> self) where T : struct
        {
            TypeEventSystem.Global.UnRegister<T>(self.OnEvent);
        }
    }

    #endregion

    #region IOC

    public class IocContainer
    {
        /// <summary>
        ///     实例
        /// </summary>
        public Dictionary<Type, object> Instances = new();

        /// <summary>
        ///     注册
        /// </summary>
        /// <param name="instance"></param>
        /// <typeparam name="T"></typeparam>
        public void Register<T>(T instance)
        {
            var key = typeof(T);

            if (Instances.ContainsKey(key))
                Instances[key] = instance;
            else
                Instances.Add(key, instance);
        }

        /// <summary>
        ///     获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T Get<T>() where T : class
        {
            var key = typeof(T);

            object retObj;

            if (Instances.TryGetValue(key, out retObj)) return retObj as T;

            return null;
        }
    }

    #endregion

    #region BindableProperty

    public class BindableProperty<T>
    {
        private Action<T> _onValueChanged = v => { };
        private T _value;

        public BindableProperty(T defaultValue = default)
        {
            _value = defaultValue;
        }

        public T Value
        {
            get => _value;
            set
            {
                if (value == null && _value == null) return;

                if (value != null && value.Equals(_value)) return;

                _value = value;
                _onValueChanged?.Invoke(value);
            }
        }

        public IUnRegister Register(Action<T> onValueChanged)
        {
            _onValueChanged += onValueChanged;
            return new BindablePropertyUnRegister<T>
            {
                BindableProperty = this,
                OnValueChanged = onValueChanged
            };
        }

        public IUnRegister RegisterWithInitValue(Action<T> onValueChanged)
        {
            onValueChanged(_value);
            return Register(onValueChanged);
        }

        // a.Value == b.Value
        public static implicit operator T(BindableProperty<T> property)
        {
            return property.Value;
        }

        public override string ToString()
        {
            return Value.ToString();
        }

        public void UnRegister(Action<T> onValueChanged)
        {
            _onValueChanged -= onValueChanged;
        }
    }

    public class BindablePropertyUnRegister<T> : IUnRegister
    {
        public BindableProperty<T> BindableProperty { get; set; }

        public Action<T> OnValueChanged { get; set; }

        public void UnRegister()
        {
            BindableProperty.UnRegister(OnValueChanged);

            BindableProperty = null;
            OnValueChanged = null;
        }
    }

    #endregion

    #region SingletonKit

    /// <summary>
    ///     单例接口
    /// </summary>
    public interface ISingleton
    {
        /// <summary>
        ///     单例初始化(继承当前接口的类都需要实现该方法)
        /// </summary>
        void OnSingletonInit();
    }

    /// <summary>
    ///     普通类的单例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class Singleton<T> : ISingleton where T : Singleton<T>
    {
        /// <summary>
        ///     静态实例
        /// </summary>
        protected static T mInstance;

        /// <summary>
        ///     标签锁：确保当一个线程位于代码的临界区时，另一个线程不进入临界区。
        ///     如果其他线程试图进入锁定的代码，则它将一直等待（即被阻止），直到该对象被释放
        /// </summary>
        private static readonly object mLock = new();

        /// <summary>
        ///     静态属性
        /// </summary>
        public static T Instance
        {
            get
            {
                lock (mLock)
                {
                    if (mInstance == null) mInstance = SingletonCreator.CreateSingleton<T>();
                }

                return mInstance;
            }
        }

        /// <summary>
        ///     单例初始化方法
        /// </summary>
        public virtual void OnSingletonInit()
        {
        }

        /// <summary>
        ///     资源释放
        /// </summary>
        public virtual void Dispose()
        {
            mInstance = null;
        }
    }

    /// <summary>
    ///     属性单例类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class SingletonProperty<T> where T : class, ISingleton
    {
        /// <summary>
        ///     静态实例
        /// </summary>
        private static T mInstance;

        /// <summary>
        ///     标签锁
        /// </summary>
        private static readonly object mLock = new();

        /// <summary>
        ///     静态属性
        /// </summary>
        public static T Instance
        {
            get
            {
                lock (mLock)
                {
                    if (mInstance == null) mInstance = SingletonCreator.CreateSingleton<T>();
                }

                return mInstance;
            }
        }

        /// <summary>
        ///     资源释放
        /// </summary>
        public static void Dispose()
        {
            mInstance = null;
        }
    }

    /// <summary>
    ///     普通单例创建类
    /// </summary>
    internal static class SingletonCreator
    {
        /// <summary>
        ///     单元测试模式 标签
        /// </summary>
        public static bool IsUnitTestMode { get; set; }

        private static T CreateNonPublicConstructorObject<T>() where T : class
        {
            var type = typeof(T);
            // 获取私有构造函数
            var constructorInfos = type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);

            // 获取无参构造函数
            var ctor = Array.Find(constructorInfos, c => c.GetParameters().Length == 0);

            if (ctor == null) throw new Exception("Non-Public Constructor() not found! in " + type);

            return ctor.Invoke(null) as T;
        }

        public static T CreateSingleton<T>() where T : class, ISingleton
        {
            var type = typeof(T);
            var monoBehaviourType = typeof(MonoBehaviour);

            if (monoBehaviourType.IsAssignableFrom(type)) return CreateMonoSingleton<T>();

            var instance = CreateNonPublicConstructorObject<T>();
            instance.OnSingletonInit();
            return instance;
        }

        /// <summary>
        ///     查找Obj（一个嵌套查找Obj的过程）
        /// </summary>
        /// <param name="root">父节点</param>
        /// <param name="subPath">拆分后的路径节点</param>
        /// <param name="index">下标</param>
        /// <param name="build">true</param>
        /// <param name="dontDestroy">不要销毁 标签</param>
        /// <returns></returns>
        private static GameObject FindGameObject(GameObject root, string[] subPath, int index, bool build,
            bool dontDestroy)
        {
            GameObject client = null;

            if (root == null)
            {
                client = GameObject.Find(subPath[index]);
            }
            else
            {
                var child = root.transform.Find(subPath[index]);
                if (child != null) client = child.gameObject;
            }

            if (client == null)
                if (build)
                {
                    client = new GameObject(subPath[index]);
                    if (root != null) client.transform.SetParent(root.transform);

                    if (dontDestroy && index == 0 && !IsUnitTestMode) Object.DontDestroyOnLoad(client);
                }

            if (client == null) return null;

            return ++index == subPath.Length ? client : FindGameObject(client, subPath, index, build, dontDestroy);
        }

        /// <summary>
        ///     泛型方法：创建MonoBehaviour单例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static T CreateMonoSingleton<T>() where T : class, ISingleton
        {
            T instance = null;
            var type = typeof(T);

            //判断T实例存在的条件是否满足
            if (!IsUnitTestMode && !Application.isPlaying)
                return instance;

            //判断当前场景中是否存在T实例
            instance = Object.FindObjectOfType(type) as T;
            if (instance != null)
            {
                instance.OnSingletonInit();
                return instance;
            }

            //MemberInfo：获取有关成员属性的信息并提供对成员元数据的访问
            MemberInfo info = typeof(T);
            //获取T类型 自定义属性，并找到相关路径属性，利用该属性创建T实例
            var attributes = info.GetCustomAttributes(true);
            foreach (var atribute in attributes)
            {
                var defineAttri = atribute as MonoSingletonPath;
                if (defineAttri == null) continue;

                instance = CreateComponentOnGameObject<T>(defineAttri.PathInHierarchy, true);
                break;
            }

            //如果还是无法找到instance  则主动去创建同名Obj 并挂载相关脚本 组件
            if (instance == null)
            {
                var obj = new GameObject(typeof(T).Name);
                if (!IsUnitTestMode)
                    Object.DontDestroyOnLoad(obj);
                instance = obj.AddComponent(typeof(T)) as T;
            }

            instance.OnSingletonInit();
            return instance;
        }

        /// <summary>
        ///     在GameObject上创建T组件（脚本）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path">路径（应该就是Hierarchy下的树结构路径）</param>
        /// <param name="dontDestroy">不要销毁 标签</param>
        /// <returns></returns>
        private static T CreateComponentOnGameObject<T>(string path, bool dontDestroy) where T : class
        {
            var obj = FindGameObject(path, true, dontDestroy);
            if (obj == null)
            {
                obj = new GameObject("Singleton of " + typeof(T).Name);
                if (dontDestroy && !IsUnitTestMode) Object.DontDestroyOnLoad(obj);
            }

            return obj.AddComponent(typeof(T)) as T;
        }

        /// <summary>
        ///     查找Obj（对于路径 进行拆分）
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="build">true</param>
        /// <param name="dontDestroy">不要销毁 标签</param>
        /// <returns></returns>
        private static GameObject FindGameObject(string path, bool build, bool dontDestroy)
        {
            if (string.IsNullOrEmpty(path)) return null;

            var subPath = path.Split('/');
            if (subPath == null || subPath.Length == 0) return null;

            return FindGameObject(null, subPath, 0, build, dontDestroy);
        }
    }

    /// <summary>
    ///     静态类：MonoBehaviour类的单例
    ///     泛型类：Where约束表示T类型必须继承MonoSingleton<T>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class MonoSingleton<T> : MonoBehaviour, ISingleton where T : MonoSingleton<T>
    {
        /// <summary>
        ///     静态实例
        /// </summary>
        protected static T mInstance;

        /// <summary>
        ///     当前应用程序是否结束 标签
        /// </summary>
        protected static bool mOnApplicationQuit;

        /// <summary>
        ///     静态属性：封装相关实例对象
        /// </summary>
        public static T Instance
        {
            get
            {
                if (mInstance == null && !mOnApplicationQuit) mInstance = SingletonCreator.CreateMonoSingleton<T>();

                return mInstance;
            }
        }

        /// <summary>
        ///     判断当前应用程序是否退出
        /// </summary>
        public static bool IsApplicationQuit => mOnApplicationQuit;

        /// <summary>
        ///     释放当前对象
        /// </summary>
        protected virtual void OnDestroy()
        {
            mInstance = null;
        }

        /// <summary>
        ///     应用程序退出：释放当前对象并销毁相关GameObject
        /// </summary>
        protected virtual void OnApplicationQuit()
        {
            mOnApplicationQuit = true;
            if (mInstance == null) return;
            Destroy(mInstance.gameObject);
            mInstance = null;
        }

        /// <summary>
        ///     实现接口的单例初始化
        /// </summary>
        public virtual void OnSingletonInit()
        {
        }

        /// <summary>
        ///     资源释放
        /// </summary>
        public virtual void Dispose()
        {
            if (SingletonCreator.IsUnitTestMode)
            {
                var curTrans = transform;
                do
                {
                    var parent = curTrans.parent;
                    DestroyImmediate(curTrans.gameObject);
                    curTrans = parent;
                } while (curTrans != null);

                mInstance = null;
            }
            else
            {
                Destroy(gameObject);
            }
        }
    }

    /// <summary>
    ///     MonoSingleton路径
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)] //这个特性只能标记在Class上
    public class MonoSingletonPath : Attribute
    {
        public MonoSingletonPath(string pathInHierarchy)
        {
            PathInHierarchy = pathInHierarchy;
        }

        public string PathInHierarchy { get; }
    }

    /// <summary>
    ///     继承Mono的属性单例？
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class MonoSingletonProperty<T> where T : MonoBehaviour, ISingleton
    {
        private static T mInstance;

        public static T Instance
        {
            get
            {
                if (null == mInstance) mInstance = SingletonCreator.CreateMonoSingleton<T>();

                return mInstance;
            }
        }

        public static void Dispose()
        {
            if (SingletonCreator.IsUnitTestMode)
                Object.DestroyImmediate(mInstance.gameObject);
            else
                Object.Destroy(mInstance.gameObject);

            mInstance = null;
        }
    }

    /// <summary>
    ///     如果跳转到新的场景里已经有了实例，则不创建新的单例（或者创建新的单例后会销毁掉新的单例）
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class PersistentMonoSingleton<T> : MonoBehaviour where T : Component
    {
        protected static T mInstance;
        protected bool mEnabled;

        /// <summary>
        ///     Singleton design pattern
        /// </summary>
        /// <value>The instance.</value>
        public static T Instance
        {
            get
            {
                if (mInstance == null)
                {
                    mInstance = FindObjectOfType<T>();
                    if (mInstance == null)
                    {
                        var obj = new GameObject();
                        mInstance = obj.AddComponent<T>();
                    }
                }

                return mInstance;
            }
        }

        /// <summary>
        ///     On awake, we check if there's already a copy of the object in the scene. If there's one, we destroy it.
        /// </summary>
        protected virtual void Awake()
        {
            if (!Application.isPlaying) return;

            if (mInstance == null)
            {
                //If I am the first instance, make me the Singleton
                mInstance = this as T;
                DontDestroyOnLoad(transform.gameObject);
                mEnabled = true;
            }
            else
            {
                //If a Singleton already exists and you find
                //another reference in scene, destroy it!
                if (this != mInstance) Destroy(gameObject);
            }
        }
    }

    /// <summary>
    ///     如果跳转到新的场景里已经有了实例，则删除已有示例，再创建新的实例
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ReplaceableMonoSingleton<T> : MonoBehaviour where T : Component
    {
        protected static T mInstance;
        public float InitializationTime;

        /// <summary>
        ///     Singleton design pattern
        /// </summary>
        /// <value>The instance.</value>
        public static T Instance
        {
            get
            {
                if (mInstance == null)
                {
                    mInstance = FindObjectOfType<T>();
                    if (mInstance == null)
                    {
                        var obj = new GameObject();
                        obj.hideFlags = HideFlags.HideAndDontSave;
                        mInstance = obj.AddComponent<T>();
                    }
                }

                return mInstance;
            }
        }

        /// <summary>
        ///     On awake, we check if there's already a copy of the object in the scene. If there's one, we destroy it.
        /// </summary>
        protected virtual void Awake()
        {
            if (!Application.isPlaying) return;

            InitializationTime = Time.time;

            DontDestroyOnLoad(gameObject);
            // we check for existing objects of the same type
            var check = FindObjectsOfType<T>();

            foreach (var searched in check)
                if (searched != this)
                    // if we find another object of the same type (not this), and if it's older than our current object, we destroy it.
                    if (searched.GetComponent<ReplaceableMonoSingleton<T>>().InitializationTime < InitializationTime)
                        Destroy(searched.gameObject);

            if (mInstance == null) mInstance = this as T;
        }
    }

    #endregion
}